﻿#region zh-CHS 2006 - 2007 DemoSoft 团队 | en 2006 - 2007 DemoSoft Team

//     NOTES
// ---------------
//
// This file is a part of the G.O.S.E(Game Online Server Engine) for .NET.
//
//                 2006-2007 DemoSoft Team
//
//
// First Version : by H.Q.Cai - mailto:caihuanqing@hotmail.com

/***************************************************************************
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU Lesser General Public License as published
 *   by the Free Software Foundation; either version 2.1 of the License, or
 *   (at your option) any later version.
 *
 ***************************************************************************/

#region zh-CHS 包含名字空间 | en Include namespace
using System;
using System.Text;
using System.Threading;
using System.Collections.Generic;
using Demo_G.O.S.E.ServerEngine.Common;
using System.Diagnostics;
using Demo_G.O.S.E.ServerEngine.Util;
#endregion

namespace Demo_G.O.S.E.ServerEngine.Network
{
    /// <summary>
    /// 数据输出包的缓冲区,如果数据过长就等处理缓存发送时发送数据( 小于 512K 时 )
    /// 之所以小于 512K 是因为TCP-IP发送数据时总是发送至客户端彼此确认完毕后才通知返回的,如果过大网络延迟时会严重影响网络的通讯.
    /// </summary>
    [MultiThreadedSupportgAttribute( "当前的类所有成员都可锁定,支持多线程操作" )]
    internal class SendQueue
    {
        #region zh-CHS 内部 Gram 类 | en Internal Gram Class
        /// <summary>
        /// 
        /// </summary>
        internal class Gram : IRelease
        {
            #region zh-CHS 构造和初始化和清理 | en Constructors and Initializers and Dispose
            /// <summary>
            /// 私有的构造类
            /// </summary>
            private Gram()
            {
            }
            #endregion

            #region zh-CHS 属性 | en Properties
            #region zh-CHS 私有成员变量 | en Private Member Variables
            /// <summary>
            /// 缓冲区的字节
            /// </summary>
            private byte[] m_Buffer;
            #endregion
            /// <summary>
            /// 缓冲区的字节
            /// </summary>
            public byte[] Buffer
            {
                get { return m_Buffer; }
            }

            #region zh-CHS 私有成员变量 | en Private Member Variables
            /// <summary>
            /// 缓冲区的长度
            /// </summary>
            private long m_iLength;
            #endregion
            /// <summary>
            /// 缓冲区的长度
            /// </summary>
            public long Length
            {
                get { return m_iLength; }
            }

            /// <summary>
            /// 缓冲区的剩余的有效空间
            /// </summary>
            public long Available
            {
                get { return ( m_Buffer.Length - m_iLength ); }
            }

            /// <summary>
            /// 缓冲区是否已经满了
            /// </summary>
            public bool IsFull
            {
                get { return ( m_iLength >= m_Buffer.Length ); }
            }
            #endregion

            #region zh-CHS 方法 | en Method
            /// <summary>
            /// 
            /// </summary>
            /// <param name="byteBuffer"></param>
            /// <param name="iOffset"></param>
            /// <param name="iLength"></param>
            /// <returns></returns>
            internal long Write( byte[] byteBuffer, long iOffset, long iLength )
            {
                // 获取可以写当前缓冲区的字节数
                long iWrite = Math.Min( iLength, Available );

                // 写入数据
                System.Buffer.BlockCopy( byteBuffer, (int)iOffset, m_Buffer, (int)m_iLength, (int)iWrite );

                // 跟新缓冲区的长度
                m_iLength += iWrite;

                return iWrite;
            }

            #region zh-CHS 私有成员变量 | en Private Member Variables
            /// <summary>
            /// 
            /// </summary>
            private int m_bIsRelease = 0;
            #endregion
            /// <summary>
            /// 
            /// </summary>
            public void Release()
            {
                if ( Interlocked.Exchange( ref m_bIsRelease, 1 ) == 0 && m_Buffer != null )
                {
                    // 把数据返回进内存池
                    SendQueue.ReleaseBuffer( m_Buffer );
                    m_Buffer = null;
                    m_iLength = 0;
                }
            }
            #endregion

            #region zh-CHS 静态方法 | en Static Method
            /// <summary>
            /// 请求Gram类
            /// </summary>
            /// <returns></returns>
            public static Gram Instance()
            {
                Gram sendGram = new Gram();

                sendGram.m_Buffer = SendQueue.AcquireBuffer();
                sendGram.m_iLength = 0;
                sendGram.m_bIsRelease = 0;

                return sendGram;
            }
            #endregion
        }
        #endregion

        #region zh-CHS 私有成员变量 | en Private Member Variables
        /// <summary>
        /// 当Flush发出的数据(最后发出的数据块)
        /// </summary>
        private Gram m_GramFlushBuffer = null;
        /// <summary>
        /// 等待需要发出的数据
        /// </summary>
        private Queue<Gram> m_GramPendingBuffer = new Queue<Gram>();
        /// <summary>
        /// 等待需要发出的数据锁
        /// </summary>
        private ReaderWriterLockSlim m_LockFlushAndPending = new ReaderWriterLockSlim();
        #endregion

        #region zh-CHS 属性 | en Properties
        /// <summary>
        /// 当前需Flush发送的数据是否存在
        /// </summary>
        public bool IsFlushReady
        {
            get { return ( m_GramPendingBuffer.Count <= 0 && m_GramFlushBuffer != null ); }
        }

        /// <summary>
        /// 当前需发送的数据是否空的
        /// </summary>
        public bool IsEmpty
        {
            get { return ( m_GramPendingBuffer.Count <= 0 && m_GramFlushBuffer == null ); }
        }
        #endregion

        #region zh-CHS 静态属性 | en Static Properties
        #region zh-CHS 私有成员变量 | en Private Member Variables
        /// <summary>
        /// 缓冲的数据大小
        /// </summary>
        private static int s_CoalesceBufferSize = 512;
        #endregion
        /// <summary>
        /// 合并缓冲的数据大小
        /// </summary>
        public static int CoalesceBufferSize
        {
            get { return s_CoalesceBufferSize; }
            set
            {
                if ( s_CoalesceBufferSize == value )
                    return;

                s_CoalesceBufferSize = value;

                if ( s_UnusedBuffers != null )
                    s_UnusedBuffers.Release();

                s_UnusedBuffers = new BufferPool( "SendQueue - CoalescedBuffer", 1024, s_CoalesceBufferSize );
            }
        }
        #endregion

        #region zh-CHS 方法 | en Method
        #region zh-CHS 私有成员变量 | en Private Member Variables
        /// <summary>
        /// 可能是windows操作系统的最大可发送的字节数
        /// </summary>
        private const int PENDING_MAX_BUFFER = 96 * 1024;
        #endregion
        /// <summary>
        /// 如果数据满了,且缓冲区内的数据是空的则返回需要发送的数据
        /// 调用Enqueue(...)后调用Dequeue(...),不能直接调用Dequeue(...)
        /// </summary>
        /// <param name="byteBuffer"></param>
        /// <param name="iOffset"></param>
        /// <param name="iLength"></param>
        /// <returns></returns>
        public Gram Enqueue( byte[] byteBuffer, long iOffset, long iLength )
        {
            if ( byteBuffer == null )
            {
                Debug.WriteLine( "SendQueue.Enqueue(...) - byteBuffer == null error!" );
                return null;
            }
            else if ( ( iOffset >= 0 && iOffset < byteBuffer.Length ) == false)
            {
                Debug.WriteLine( "SendQueue.Enqueue(...) - ( iOffset >= 0 && iOffset < byteBuffer.Length ) == false error!" );
                return null;
            }
            else if ( iLength < 0 || iLength > byteBuffer.Length ) // 如果iLength == 0就返回空
            {
                Debug.WriteLine( "SendQueue.Enqueue(...) - iLength < 0 || iLength > byteBuffer.Length error!" );
                return null;
            }
            else if ( ( byteBuffer.Length - iOffset ) < iLength )
            {
                Debug.WriteLine( "SendQueue.Enqueue(...) - byteBuffer.Length - iOffset error!" );
                return null;
            }
            else if ( iLength == 0 ) // 如果iLength == 0就跳过
            {
                Debug.WriteLine( "SendQueue.Enqueue(...) - iLength == 0 warning!" );
                return null;
            }

            // 现在全部需要发送的字节
            long iExistingBytes = ( m_GramPendingBuffer.Count * s_CoalesceBufferSize ) + ( m_GramFlushBuffer == null ? 0 : m_GramFlushBuffer.Length );

            // 全部字节加需要添加的字节,如果大于PENDING_MAX_BUFFER就异常,等待的数据太多
            if ( ( iExistingBytes + iLength ) > PENDING_MAX_BUFFER )
                Debug.WriteLine( "SendQueue.Enqueue(...) - ( iExistingBytes + iLength ) > PENDING_MAX_BUFFER warning!" );

            Gram sendGram = null;

            ReaderWriterLockSlimEx.EnterWriteLock( m_LockFlushAndPending );
            {
                do
                {
                    if ( m_GramFlushBuffer == null )
                    {
                        // nothing yet buffered
                        m_GramFlushBuffer = Gram.Instance();
                        if ( m_GramFlushBuffer == null )
                        {
                            Debug.WriteLine( "SendQueue.Enqueue(...) - m_GramFlushBuffer == null error!" );
                            break;
                        }
                    }

                    // 当前已经写入的字节
                    long iBytesWritten = m_GramFlushBuffer.Write( byteBuffer, iOffset, iLength );

                    iOffset += iBytesWritten;
                    iLength -= iBytesWritten;

                    // 如果数据没有满,且数据写入完毕则退出,返回空,不添加到集合内
                    if ( m_GramFlushBuffer.IsFull )
                    {
                        // 如果是零则返回当前需要发送的数据,并用于防治FlushReady()时已添加m_GramPendingBuffer不需要返回sendGram的问题
                        if ( m_GramPendingBuffer.Count <= 0 )
                            sendGram = m_GramFlushBuffer;

                        // 如果满了添加到集合内的尾处
                        m_GramPendingBuffer.Enqueue( m_GramFlushBuffer );
                        m_GramFlushBuffer = null;　// 置空再次请求缓存
                    }
                } while ( iLength > 0 );
            }
            ReaderWriterLockSlimEx.ExitWriteLock( m_LockFlushAndPending );

            return sendGram;
        }

        /// <summary>
        /// 获取当前的数据
        /// </summary>
        /// <returns></returns>
        public Gram Dequeue()
        {
            Gram sendGram = null;

            ReaderWriterLockSlimEx.EnterWriteLock( m_LockFlushAndPending );
            {
                if ( m_GramPendingBuffer.Count > 0 )
                {
                    // 先释放先前的数据(给出头部数据)
                    m_GramPendingBuffer.Dequeue().Release();

                    if ( m_GramPendingBuffer.Count > 0 )
                        sendGram = m_GramPendingBuffer.Peek();　// 再给出数据
                }
            }
            ReaderWriterLockSlimEx.ExitWriteLock( m_LockFlushAndPending );

            return sendGram;
        }

        /// <summary>
        /// 检查当前的数据,调用FlushReady(...)后调用Dequeue(...),不能直接调用Dequeue(...)
        /// </summary>
        /// <returns></returns>
        public Gram FlushReady()
        {
            Gram sendGram = null;

            ReaderWriterLockSlimEx.EnterWriteLock( m_LockFlushAndPending );
            {
                // 只有在m_GramFlushBuffer里面的数据不是满的时候和等待的数据是空的时候才调用
                if ( m_GramPendingBuffer.Count <= 0 && m_GramFlushBuffer != null )
                {
                    sendGram = m_GramFlushBuffer;
                    m_GramFlushBuffer = null;

                    // 把当前的数据放在缓冲集合内(放在结尾)
                    // 因为m_Pending.Count == 0 所以当调用Dequeue(...)时会自动释放掉
                    m_GramPendingBuffer.Enqueue( sendGram );
                }
            }
            ReaderWriterLockSlimEx.ExitWriteLock( m_LockFlushAndPending );

            return sendGram;
        }

        /// <summary>
        /// 清除数据
        /// </summary>
        public void Clear()
        {
            ReaderWriterLockSlimEx.EnterWriteLock( m_LockFlushAndPending );
            {
                while ( m_GramPendingBuffer.Count > 0 )
                    m_GramPendingBuffer.Dequeue().Release();

                if ( m_GramFlushBuffer != null )
                {
                    m_GramFlushBuffer.Release();
                    m_GramFlushBuffer = null;
                }
            }
            ReaderWriterLockSlimEx.ExitWriteLock( m_LockFlushAndPending );
        }
        #endregion

        #region zh-CHS 私有静态方法 | en Private Static Method
        #region zh-CHS 私有静态成员变量 | en Private Static Member Variables
        /// <summary>
        /// 
        /// </summary>
        private static BufferPool s_UnusedBuffers = new BufferPool( "SendQueue - CoalescedBuffer", 1024, s_CoalesceBufferSize );
        #endregion
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        internal static byte[] AcquireBuffer()
        {
            return s_UnusedBuffers.AcquireBuffer();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="byteBuffer"></param>
        internal static void ReleaseBuffer( byte[] byteBuffer )
        {
            if ( byteBuffer != null )
            {
                if ( byteBuffer.Length == s_CoalesceBufferSize ) // 可能修改过m_CoalesceBufferSize如果不同就抛弃它
                    s_UnusedBuffers.ReleaseBuffer( byteBuffer );
            }
        }
        #endregion
    }
}
#endregion